package gui;

import data.ApplicationProperties;
import data.UserPreferences;
import java.awt.Dialog.ModalityType;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Vector;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.ListModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import kit.Component;
import midi.MidiHelpers;
import tablature.TimeSignature;

/**
 * Class: SetupWindow.java
 * Description: Contains a GUI that sets up the application.
 * @author et
 */
public class SetupWindow extends JPanel implements ChangeListener, ActionListener, ListSelectionListener
{

    private UserPreferences up = UserPreferences.getInstance();

    private DefaultTableModel componentTableModel = new DefaultTableModel();

    // A single instance of the class.
    private static SetupWindow instance;

    /**
     * Returns a singleton instance of this class.
     * @return instance - a single instance of this class.
      */
    public static SetupWindow getInstance()
    {
        if (instance == null)
        {
            instance = new SetupWindow();
        }
        return instance;
    }

    /**
     * Constructor for SetupWindow.
     */
    private SetupWindow()
    {
        initComponents();

        setupMidiInComboBox();
        setupTimingComboBox();
        setupTempo();
        updateComponentTable();
        
        updateEnabledButtons();

        openButton.addActionListener(this);
        tempoSlider.addChangeListener(this);
        countdownSpinner.addChangeListener(this);
        componentsTable.getSelectionModel().addListSelectionListener(this);

        updateTempo();

        
    }

    /**
     * Gets the main component of this class.
     * @return the JPanel, this.
     */
    public JPanel getMainComponent()
    {
        return this;
    }


    /**
     * Gets the requested background track
     * @return the background track.
     */
    public String getBackgroundTrack()
    {
        return filenameTextField.getText();
    }

    /**
     * Gets the countdown seconds
     * @return the countdown seconds.
     */
    public int getCountdownSeconds()
    {
        return (Integer) countdownSpinner.getValue();
    }

    /**
     * Sets up the midi in combo box with the available devices.
     */
    public void setupMidiInComboBox()
    {
        ListModel midiInList = new DefaultComboBoxModel(MidiHelpers.getInputMidiDevices());
        midiInComboBox.setModel((ComboBoxModel) midiInList);
        midiInComboBox.setSelectedItem(up.getMidiIn());
    }

    /**
     * Sets up the timing combo box with all the available time signatures.
     */
    private void setupTimingComboBox()
    {
        DefaultComboBoxModel timingList = new DefaultComboBoxModel(new Vector <TimeSignature> ());
        timingList.addElement(TimeSignature.FOURFOUR);
        timingComboBox.setModel(timingList);
    }

    /**
     * Sets up the tempo with the last tempo selected.
     */
    private void setupTempo()
    {
        tempoSlider.setValue(up.getTempo());
        metronomeSoundCheckBox.setSelected(up.hasBackgroundMetronomeSound());
    }

    /**
     * Updates the user preference for when the sound check box is clicked.
     */
    private void metronomeSoundCheckBoxClicked()
    {
        up.setBackgroundMetronomeSound(metronomeSoundCheckBox.isSelected());
    }

    /**
     * Updates the component table with all
     * the saved components.
     */
    private void updateComponentTable()
    {
        Vector colNames = new Vector();
        colNames.add("Component");
        colNames.add("Name");
        colNames.add("Short name");
        colNames.add("Hit note");
        colNames.add("Assignment");

        Vector data = new Vector();
        
        for (Component c : up.getComponents())
        {
            Vector rowData = new Vector();
            rowData.add(c);
            rowData.add(c.getName());
            rowData.add(c.getShortName());
            rowData.add(c.getRegHit());
            rowData.add(c.getAssignment());

            data.add(rowData);
        }

        componentTableModel = new DefaultTableModel(data, colNames);

        componentsTable.setModel(componentTableModel);
    }



    /**
     * Enables the buttons if a component is selected.
     */
    private void updateEnabledButtons()
    {
        if (componentsTable.getSelectedRow() == -1)
        {
            editButton.setEnabled(false);
            removeButton.setEnabled(false);
            moveUpButton.setEnabled(false);
            moveDownButton.setEnabled(false);
        }
        else
        {
            editButton.setEnabled(true);
            removeButton.setEnabled(true);
            moveUpButton.setEnabled(true);
            moveDownButton.setEnabled(true);
        }
    }

    /**
     * Updates the tempo text when the user slides
     * the tempo bar.
     */
    private void updateTempo()
    {
        tempoLabel.setText("" + tempoSlider.getValue() + " BPM");
        up.setTempo(tempoSlider.getValue());
    }



    /**
     * The user selected a different MIDI in link.
     */
    private void midiInSelected()
    {
        String midiIn = (String) midiInComboBox.getSelectedItem();
        up.setMidiIn(midiIn);
    }

    /**
     * The user selected a different time signature.
     */
    private void timeSignatureSelected()
    {
        TimeSignature ts = (TimeSignature) timingComboBox.getSelectedItem();
        up.setTimeSignature(ts);
    }

    /**
     * Removes a component from the component table.
     */
    private void removeComponent()
    {
        int selectedRow = componentsTable.getSelectedRow();
        Component c = (Component) componentsTable.getValueAt(selectedRow, 0);

        up.removeComponent(c);
        updateComponentTable();

    }

    /**
     * Moves a component up in the component table.
     */
    private void moveComponentUp()
    {
        int selectedRow = componentsTable.getSelectedRow();
        Component c = (Component) componentsTable.getValueAt(selectedRow, 0);
        up.moveComponentUp(c);

        updateComponentTable();
    }

    /**
     * Moves a component down in the component table.
     */
    private void moveComponentDown()
    {
        int selectedRow = componentsTable.getSelectedRow();
        Component c = (Component) componentsTable.getValueAt(selectedRow, 0);
        up.moveComponentDown(c);

        updateComponentTable();
    }

    /**
     * Shows the modify component window for adding a component.
     */
    protected void showAddComponentWindowDialog()
    {
        ModifyComponentWindow addComponentWindow = new ModifyComponentWindow();

        Window windowAncestor = SwingUtilities.getWindowAncestor(this);
        // create my dialog when I need it
        JDialog dialog = new JDialog(windowAncestor, ApplicationProperties.ADD_COMPONENT, ModalityType.APPLICATION_MODAL);

        // add my infoDialog's JPanel into the dialog's contentPane
        dialog.getContentPane().add(addComponentWindow.getMainComponent());
        dialog.pack();
        dialog.setLocationRelativeTo(null);
        dialog.setVisible(true);

        updateComponentTable();
    }

    /**
     * Show the modify component window for editing a component.
     */
    protected void showEditComponentWindowDialog()
    {
        int selected = componentsTable.getSelectedRow();
        ModifyComponentWindow editComponentWindow = new ModifyComponentWindow((Component) componentTableModel.getValueAt(selected, 0), true);

        Window windowAncestor = SwingUtilities.getWindowAncestor(this);
        // create my dialog when I need it
        JDialog dialog = new JDialog(windowAncestor, ApplicationProperties.EDIT_COMPONENT, ModalityType.APPLICATION_MODAL);

        // add my infoDialog's JPanel into the dialog's contentPane
        dialog.getContentPane().add(editComponentWindow.getMainComponent());
        dialog.pack();
        dialog.setLocationRelativeTo(null);
        dialog.setVisible(true);

        updateComponentTable();
    }

    /**
     * User moved the tempo slider
     * @param e - change event.
     */
    public void stateChanged(ChangeEvent e)
    {
        if (e.getSource() == tempoSlider)
        {
            updateTempo();
        }
    }

    /**
     * User wants to open the file chooser
     * @param e - action event.
     */
    public void actionPerformed(ActionEvent e)
    {
        if (e.getSource() == openButton)
        {
            JFileChooser fc = new JFileChooser();
            fc.addChoosableFileFilter(new SongFilter());


            int returnVal = fc.showOpenDialog(this);

            if (returnVal == JFileChooser.APPROVE_OPTION)
            {
                File file = fc.getSelectedFile();
                filenameTextField.setText(file.toString());
            }

        }
    }

    /**
     * Selected a row in the table.
     * @param e - list selection event
     */
    public void valueChanged(ListSelectionEvent e)
    {
        updateEnabledButtons();
    }


    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        setupWindowTabbedPane = new javax.swing.JTabbedPane();
        generalPanel = new javax.swing.JPanel();
        generalContainerPanel = new javax.swing.JPanel();
        midiInPanel = new javax.swing.JPanel();
        midiInComboBox = new javax.swing.JComboBox();
        backgroundTrackPanel = new javax.swing.JPanel();
        filenameTextField = new javax.swing.JTextField();
        openButton = new javax.swing.JButton();
        countdownTimerPanel = new javax.swing.JPanel();
        countdownSpinner = new javax.swing.JSpinner();
        secondsLabel = new javax.swing.JLabel();
        timingPanel = new javax.swing.JPanel();
        timingComboBox = new javax.swing.JComboBox();
        tempoPanel = new javax.swing.JPanel();
        subTempoPanel = new javax.swing.JPanel();
        tempoSlider = new javax.swing.JSlider();
        tempoLabel = new javax.swing.JLabel();
        metronomeSoundCheckBox = new javax.swing.JCheckBox();
        componentsPanel = new javax.swing.JPanel();
        componentListPanel = new javax.swing.JPanel();
        moveUpButton = new javax.swing.JButton();
        moveDownButton = new javax.swing.JButton();
        addButton = new javax.swing.JButton();
        editButton = new javax.swing.JButton();
        removeButton = new javax.swing.JButton();
        componentsScrollPane = new javax.swing.JScrollPane();
        componentsTable = new javax.swing.JTable();

        midiInPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("MIDI in"));

        midiInComboBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                midiInComboBoxActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout midiInPanelLayout = new javax.swing.GroupLayout(midiInPanel);
        midiInPanel.setLayout(midiInPanelLayout);
        midiInPanelLayout.setHorizontalGroup(
            midiInPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(midiInPanelLayout.createSequentialGroup()
                .addComponent(midiInComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 174, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(51, Short.MAX_VALUE))
        );
        midiInPanelLayout.setVerticalGroup(
            midiInPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(midiInPanelLayout.createSequentialGroup()
                .addComponent(midiInComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(13, Short.MAX_VALUE))
        );

        backgroundTrackPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Background Track"));

        filenameTextField.setEditable(false);

        openButton.setFont(new java.awt.Font("Bitstream Vera Sans", 1, 12));
        openButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/img/open.png"))); // NOI18N
        openButton.setText("Open");

        javax.swing.GroupLayout backgroundTrackPanelLayout = new javax.swing.GroupLayout(backgroundTrackPanel);
        backgroundTrackPanel.setLayout(backgroundTrackPanelLayout);
        backgroundTrackPanelLayout.setHorizontalGroup(
            backgroundTrackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, backgroundTrackPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(backgroundTrackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(openButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 201, Short.MAX_VALUE)
                    .addComponent(filenameTextField, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 201, Short.MAX_VALUE))
                .addContainerGap())
        );
        backgroundTrackPanelLayout.setVerticalGroup(
            backgroundTrackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(backgroundTrackPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(openButton)
                .addGap(12, 12, 12)
                .addComponent(filenameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(29, Short.MAX_VALUE))
        );

        countdownTimerPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Countdown"));

        countdownSpinner.setModel(new javax.swing.SpinnerNumberModel(5, 0, 30, 1));

        secondsLabel.setText("Seconds");

        javax.swing.GroupLayout countdownTimerPanelLayout = new javax.swing.GroupLayout(countdownTimerPanel);
        countdownTimerPanel.setLayout(countdownTimerPanelLayout);
        countdownTimerPanelLayout.setHorizontalGroup(
            countdownTimerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(countdownTimerPanelLayout.createSequentialGroup()
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(countdownSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(secondsLabel))
        );
        countdownTimerPanelLayout.setVerticalGroup(
            countdownTimerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(countdownTimerPanelLayout.createSequentialGroup()
                .addGroup(countdownTimerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(countdownSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(secondsLabel))
                .addContainerGap(17, Short.MAX_VALUE))
        );

        timingPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Timing"));

        timingComboBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                timingComboBoxActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout timingPanelLayout = new javax.swing.GroupLayout(timingPanel);
        timingPanel.setLayout(timingPanelLayout);
        timingPanelLayout.setHorizontalGroup(
            timingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, timingPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(timingComboBox, 0, 131, Short.MAX_VALUE)
                .addContainerGap())
        );
        timingPanelLayout.setVerticalGroup(
            timingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(timingPanelLayout.createSequentialGroup()
                .addComponent(timingComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(13, Short.MAX_VALUE))
        );

        tempoPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Tempo"));

        tempoSlider.setMajorTickSpacing(40);
        tempoSlider.setMaximum(200);
        tempoSlider.setMinimum(40);
        tempoSlider.setPaintLabels(true);
        tempoSlider.setPaintTicks(true);
        tempoSlider.setValue(60);

        tempoLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);

        metronomeSoundCheckBox.setText("Sound");
        metronomeSoundCheckBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                metronomeSoundCheckBoxActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout subTempoPanelLayout = new javax.swing.GroupLayout(subTempoPanel);
        subTempoPanel.setLayout(subTempoPanelLayout);
        subTempoPanelLayout.setHorizontalGroup(
            subTempoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(subTempoPanelLayout.createSequentialGroup()
                .addGroup(subTempoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(subTempoPanelLayout.createSequentialGroup()
                        .addGap(12, 12, 12)
                        .addComponent(metronomeSoundCheckBox))
                    .addGroup(subTempoPanelLayout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(tempoSlider, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE))
                    .addGroup(subTempoPanelLayout.createSequentialGroup()
                        .addGap(77, 77, 77)
                        .addComponent(tempoLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        subTempoPanelLayout.setVerticalGroup(
            subTempoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, subTempoPanelLayout.createSequentialGroup()
                .addGroup(subTempoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(subTempoPanelLayout.createSequentialGroup()
                        .addContainerGap(23, Short.MAX_VALUE)
                        .addComponent(tempoSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED))
                    .addGroup(subTempoPanelLayout.createSequentialGroup()
                        .addComponent(tempoLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)))
                .addGap(37, 37, 37))
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, subTempoPanelLayout.createSequentialGroup()
                .addContainerGap(71, Short.MAX_VALUE)
                .addComponent(metronomeSoundCheckBox)
                .addContainerGap())
        );

        javax.swing.GroupLayout tempoPanelLayout = new javax.swing.GroupLayout(tempoPanel);
        tempoPanel.setLayout(tempoPanelLayout);
        tempoPanelLayout.setHorizontalGroup(
            tempoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(subTempoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        tempoPanelLayout.setVerticalGroup(
            tempoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(tempoPanelLayout.createSequentialGroup()
                .addComponent(subTempoPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        javax.swing.GroupLayout generalContainerPanelLayout = new javax.swing.GroupLayout(generalContainerPanel);
        generalContainerPanel.setLayout(generalContainerPanelLayout);
        generalContainerPanelLayout.setHorizontalGroup(
            generalContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(generalContainerPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(generalContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(midiInPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(backgroundTrackPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(generalContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(generalContainerPanelLayout.createSequentialGroup()
                        .addComponent(countdownTimerPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(timingPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addComponent(tempoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap())
        );
        generalContainerPanelLayout.setVerticalGroup(
            generalContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(generalContainerPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(generalContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addGroup(generalContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                        .addComponent(timingPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(countdownTimerPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addComponent(midiInPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(generalContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(tempoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(backgroundTrackPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        javax.swing.GroupLayout generalPanelLayout = new javax.swing.GroupLayout(generalPanel);
        generalPanel.setLayout(generalPanelLayout);
        generalPanelLayout.setHorizontalGroup(
            generalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(generalContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        generalPanelLayout.setVerticalGroup(
            generalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(generalContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );

        setupWindowTabbedPane.addTab("General", generalPanel);

        moveUpButton.setFont(new java.awt.Font("Bitstream Vera Sans", 1, 12));
        moveUpButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/img/up.png"))); // NOI18N
        moveUpButton.setText("Up");
        moveUpButton.setFocusPainted(false);
        moveUpButton.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        moveUpButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                moveUpButtonActionPerformed(evt);
            }
        });

        moveDownButton.setFont(new java.awt.Font("Bitstream Vera Sans", 1, 12)); // NOI18N
        moveDownButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/img/down.png"))); // NOI18N
        moveDownButton.setText("Down");
        moveDownButton.setFocusPainted(false);
        moveDownButton.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        moveDownButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                moveDownButtonActionPerformed(evt);
            }
        });

        addButton.setFont(new java.awt.Font("Bitstream Vera Sans", 1, 12));
        addButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/img/add.png"))); // NOI18N
        addButton.setText("Add");
        addButton.setFocusPainted(false);
        addButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addButtonActionPerformed(evt);
            }
        });

        editButton.setFont(new java.awt.Font("Bitstream Vera Sans", 1, 12));
        editButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/img/edit.png"))); // NOI18N
        editButton.setText("Edit");
        editButton.setFocusPainted(false);
        editButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editButtonActionPerformed(evt);
            }
        });

        removeButton.setFont(new java.awt.Font("Bitstream Vera Sans", 1, 12)); // NOI18N
        removeButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/img/remove.png"))); // NOI18N
        removeButton.setText("Remove");
        removeButton.setFocusPainted(false);
        removeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeButtonActionPerformed(evt);
            }
        });

        componentsTable.setModel(componentTableModel);
        componentsScrollPane.setViewportView(componentsTable);

        javax.swing.GroupLayout componentListPanelLayout = new javax.swing.GroupLayout(componentListPanel);
        componentListPanel.setLayout(componentListPanelLayout);
        componentListPanelLayout.setHorizontalGroup(
            componentListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(componentListPanelLayout.createSequentialGroup()
                .addGroup(componentListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addGroup(componentListPanelLayout.createSequentialGroup()
                        .addComponent(addButton)
                        .addGap(24, 24, 24)
                        .addComponent(editButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(removeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 125, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(componentsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 400, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 21, Short.MAX_VALUE)
                .addGroup(componentListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(moveUpButton, javax.swing.GroupLayout.DEFAULT_SIZE, 126, Short.MAX_VALUE)
                    .addComponent(moveDownButton, javax.swing.GroupLayout.DEFAULT_SIZE, 126, Short.MAX_VALUE))
                .addContainerGap())
        );
        componentListPanelLayout.setVerticalGroup(
            componentListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(componentListPanelLayout.createSequentialGroup()
                .addGroup(componentListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(componentListPanelLayout.createSequentialGroup()
                        .addComponent(moveUpButton)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(moveDownButton))
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, componentListPanelLayout.createSequentialGroup()
                        .addComponent(componentsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 164, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(10, 10, 10)
                        .addGroup(componentListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(editButton)
                            .addComponent(addButton)
                            .addComponent(removeButton, javax.swing.GroupLayout.DEFAULT_SIZE, 42, Short.MAX_VALUE))))
                .addContainerGap())
        );

        javax.swing.GroupLayout componentsPanelLayout = new javax.swing.GroupLayout(componentsPanel);
        componentsPanel.setLayout(componentsPanelLayout);
        componentsPanelLayout.setHorizontalGroup(
            componentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(componentsPanelLayout.createSequentialGroup()
                .addComponent(componentListPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        componentsPanelLayout.setVerticalGroup(
            componentsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(componentListPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );

        setupWindowTabbedPane.addTab("Components", componentsPanel);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(setupWindowTabbedPane, javax.swing.GroupLayout.PREFERRED_SIZE, 560, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(setupWindowTabbedPane, javax.swing.GroupLayout.DEFAULT_SIZE, 244, Short.MAX_VALUE)
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

    private void removeButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_removeButtonActionPerformed
    {//GEN-HEADEREND:event_removeButtonActionPerformed
        removeComponent();
}//GEN-LAST:event_removeButtonActionPerformed

    private void editButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_editButtonActionPerformed
    {//GEN-HEADEREND:event_editButtonActionPerformed
        showEditComponentWindowDialog();
}//GEN-LAST:event_editButtonActionPerformed

    private void addButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_addButtonActionPerformed
    {//GEN-HEADEREND:event_addButtonActionPerformed
        showAddComponentWindowDialog();
}//GEN-LAST:event_addButtonActionPerformed

    private void moveDownButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_moveDownButtonActionPerformed
    {//GEN-HEADEREND:event_moveDownButtonActionPerformed
        moveComponentDown();
}//GEN-LAST:event_moveDownButtonActionPerformed

    private void moveUpButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_moveUpButtonActionPerformed
    {//GEN-HEADEREND:event_moveUpButtonActionPerformed
        moveComponentUp();
}//GEN-LAST:event_moveUpButtonActionPerformed

    private void metronomeSoundCheckBoxActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_metronomeSoundCheckBoxActionPerformed
    {//GEN-HEADEREND:event_metronomeSoundCheckBoxActionPerformed
        metronomeSoundCheckBoxClicked();
}//GEN-LAST:event_metronomeSoundCheckBoxActionPerformed

    private void timingComboBoxActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_timingComboBoxActionPerformed
    {//GEN-HEADEREND:event_timingComboBoxActionPerformed
        timeSignatureSelected();
}//GEN-LAST:event_timingComboBoxActionPerformed

    private void midiInComboBoxActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_midiInComboBoxActionPerformed
    {//GEN-HEADEREND:event_midiInComboBoxActionPerformed
        midiInSelected();
}//GEN-LAST:event_midiInComboBoxActionPerformed


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton addButton;
    private javax.swing.JPanel backgroundTrackPanel;
    private javax.swing.JPanel componentListPanel;
    private javax.swing.JPanel componentsPanel;
    private javax.swing.JScrollPane componentsScrollPane;
    private javax.swing.JTable componentsTable;
    private javax.swing.JSpinner countdownSpinner;
    private javax.swing.JPanel countdownTimerPanel;
    private javax.swing.JButton editButton;
    private javax.swing.JTextField filenameTextField;
    private javax.swing.JPanel generalContainerPanel;
    private javax.swing.JPanel generalPanel;
    private javax.swing.JCheckBox metronomeSoundCheckBox;
    private javax.swing.JComboBox midiInComboBox;
    private javax.swing.JPanel midiInPanel;
    private javax.swing.JButton moveDownButton;
    private javax.swing.JButton moveUpButton;
    private javax.swing.JButton openButton;
    private javax.swing.JButton removeButton;
    private javax.swing.JLabel secondsLabel;
    private javax.swing.JTabbedPane setupWindowTabbedPane;
    private javax.swing.JPanel subTempoPanel;
    private javax.swing.JLabel tempoLabel;
    private javax.swing.JPanel tempoPanel;
    private javax.swing.JSlider tempoSlider;
    private javax.swing.JComboBox timingComboBox;
    private javax.swing.JPanel timingPanel;
    // End of variables declaration//GEN-END:variables
}
